I want to create a simple game, similar to what can be created with RPG Maker. What I am primarily looking for at the moment is a tutorial which can guide me on how to accomplish it without using XNA or any other specific library.
The ideal would be a step-by-step tutorial or a good, easy-to-understand example.
My goal is to do it on my own, and come to an understanding of how the overall process works with regards to animation elements relating to one another.
I've already built a simple snake game in the past using a simple tutorial, but there was no movement animation in it and that's the primary thing I'm wanting to learn next.
Edit:
All of the tutorials I have found so far use third-party libraries. I did come across this link, but I'm looking for something which doesn't include XNA.
There are a number of ways to approach the topic you're describing. I'm going to give a bit of an overview, and then hopefully provide some resources which can give you examples to get you started.
Essentially, sprite-based animations revolve around having a series of similar images which, when displayed sequentially, create the appearance of motion, similar to a flip-book.
The trick is to understand when your sprite is moving (and therefore should be animated) - and when it is standing still (and therefore should not be animated). In other words - assuming that your game's character is only supposed to move while you hold ▲, ▶, ▼ or ◀, you need to detect when one of those keys starts and stops being pressed, so that you can start/stop your animation accordingly.
Imagine that for simplicity, you only have 2 sprites. The first (left, below) represents your character standing still, and the second represents your character mid-step (right, below):
When the ▶ button is not pressed, you simply continually display the first image. When the ▶ button is pressed, you toggle between the two every x milliseconds (depending on how fast you want the animation to appear).
An animated .gif is one format in which you can contain a series of simple image frames, which are intended to be displayed as a series (and therefore create the illusion of animation). If you were to create your sprites using this format, you could use code similar to that found in this SO discussion, which provides some example code for how to use C# to animate an animated .gif and control its start/stop.
Alternatively, if you wanted to use a sprite file (like the one I included above), you could use something similar to this CodeProject code, which focuses on GDI interaction with the Windows environment in order to extract and paint a portion of the sprite onto a target canvas. By repainting every x milliseconds (as mentioned above), this can provide the same effect.
A few things to keep in mind:
You'll need to handle transparency in your sprites (the Mario sprite above, as an example, has a transparent background) - so that the background of your game environment shows through. If using GDI - this all has to do with how you call the painting methods. If using an animated .gif - the method to use depends on how you display it on your window.
For some additional resources / examples / references, check out the following resources:
Intermediate C# Game Making Tutorial - 2 - Sprites
2D Game Primer (Visual C) - an older article which talks quite a bit about the concepts of sprite animation, timing and such - and gives some example code (some DirectX in examples)
Sprite.cs - an example of some C# manipulation code for dealing with sprites and sizing (uses OpenGL, so may not be applicable)
And for Sprite development:
SpritePad - a tool for creating Sprite Sheets
http://makeagif.com/ - a tool for creating animated gifs online
http://picasion.com/ - another animated gif creator
I threw together than example of what I think it is that you were after. This example can be applied to buttons or picture boxes. I chose this way of out of simplicity.
Each instance of an animation holds a timer, and a list of images. Updating the image of the target control whenever the timer fires its event.
I have uploaded my project file here. http://mcspazzy.com/code/ParTest.zip
Hopefully it is enough to help. Just ask if you need more explanation.
The class
public class Animation
{
readonly Timer _animtimer = new Timer();
public List<Image> Frames;
public int FrameIndex;
private Button _target;
private PictureBox _ptarget;
public void Target(PictureBox target)
{
_ptarget = target;
}
public void Target(Button target)
{
_target = target;
}
public int FrameSpeed
{
get { return _animtimer.Interval; }
set { _animtimer.Interval = value; }
}
public Animation()
{
Frames = new List<Image>();
_animtimer.Interval = 100;
_animtimer.Tick += Update;
}
public void Play()
{
_animtimer.Start();
}
public void AddFrame(string file)
{
Frames.Add(Image.FromFile(file));
}
public void Stop()
{
_animtimer.Stop();
}
private void Update(object sender, EventArgs eventArgs)
{
FrameIndex++;
if (FrameIndex == Frames.Count)
{
FrameIndex = 0;
}
_target.Image = Frames[FrameIndex];
_ptarget.Image = Frames[FrameIndex];
}
public static implicit operator Image(Animation a)
{
return a.Frames[a.FrameIndex];
}
}
This was in my Form load. Can really go anywhere that stuff is initialized.
private void Form1Load(object sender, EventArgs e)
{
_testAnim.AddFrame(#"F:\Im\Black.png");
_testAnim.AddFrame(#"F:\Im\Blue.png");
_testAnim.AddFrame(#"F:\Im\Green.png");
_testAnim.AddFrame(#"F:\Im\Orange.png");
_testAnim.AddFrame(#"F:\Im\Red.png");
_testAnim.Target(ButtonTest);
_testAnim.Target(PicBox);
_testAnim.Play();
}
On quick search I found this example.
I'm not very experienced in c# graphics, but here are few points I have learned working with non-graphic oriented languages:
Declare where/what you want to draw
Create a loop to run until abort/event to end the loop (like object colliding with something)
In the loop: wait, clear the old drawing area, recalculate new position, draw in new position
If needed you can change the image to draw too, but then you need separate images for each "frame" you want to have
multithreading is a good idea, so you can separate running the graphics from other game logic
try keeping the time from clearing the drawing area and re-drawing as short as possible to prevent flickering
Keep track of the size of objects you draw, makes it easier to check for collision (like center of the sprite + radius, then you can easily calculate a circle area around it to check if two sprites are too close to each other)
Related
So I'm building a virtual gallery where the user is able to walk around and see pictures.
Now when he clicks on a picture, I want that picture to pop up take up the screen and also display some metadata about the picture, maybe read a text file related to the picture? How do I do this? I'm very new to Unity so any help will be greatly appreciated.
I'm using the below code to detect the gameobjects.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class ObjectClicker : MonoBehaviour
{
public LayerMask interactableLayermask = 6;
UnityEvent onInteract;
void Start()
{
}
void Update()
{
RaycastHit hit;
if(Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hit, 2, interactableLayermask))
{
Debug.Log(hit.collider.name);
}
}
}
```[I want to click on them and that image pops up and takes up the screen and displays some metadata about it.][1]
[1]: https://i.stack.imgur.com/skz8H.png
You can create a Panel (Unity UI), add some elements to it (a button, image, etc) and then create a UIManager object and script.
Now, you can create the methods for that UIManager:
bool showArtInfo (int index)
bool isPanelActive ()
void closePanel ()
And references for the Panel and its picture, text in the script.
You can add an array of images and text to this object. Note indices matter! (or you can use another type of collection instead of array)
Finally, to each object to which you are assigning this ObjectClicker script, you can add a unique constant index so it can indicate who it is to the UIManager. Also add a reference field for UIManager so you can bind the UI Manager script to this guy (you'll have to bind for every gallery object you have - there are better ways if you have many objects, but this is simple).
Now, inside the Update() in ObjectClicker, you can add a call like:
if(Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hit, 2, interactableLayermask)) {
if (! uiManager.isPanelActive ()) {
showArtInfo (myIndex);
}
}
How to implement showArtInfo?
You have to set the image from the array according to index, set text and enable the panel. You can also animate it to make it look nice.
How to implement isPanelActive?
Report whether it is enabled or not, if animating note this might not be enough - experiment to see what is nice.
How to set image?
I don't recall the details, but perhaps this might be useful: How do I change the source image of a Unity image component?
Also note, the Unity UI Panel does not need to be flat 2D, it can also be rendered in World Space, so it moves around with your 3D elements!
There might be many better ways to do this! If working with many objects, you can store details on the objects themselves using custom components, and GetComponent on the gameobject when hit, and pass it along to the UIManager - it will be easier to manage.
Our goal is to track a target once and then have a scene be built that you can turn around and look at, without the objects moving too much (most basic example is just 6 spheres distributed over 360° around you).
Extended Tracking seems to be the tool for the job, but out of the box it is kind of unstable and shaky, and loses positions quickly when turning away from the marker/target.
Is there any approach (I'm thinking script-wise) to build upon the standard behavior and make it more robust, e.g. retain the objects at the place they were scanned first?
If you are using Image Targets to track image, then make the following changes in the script > DefaultTrackableEventHandler.cs
protected virtual void OnTrackingFound()
{
....
....
StartCoroutine(TurnOffTracking());
}
IEnumerator TurnOffTracking()
{
yield return new WaitForSeconds(2); //Keeping a delay of 2 seconds after the image has been tracked
TrackerManager.Instance.GetTracker<ObjectTracker>().Stop(); //Tracking will be stopped and the objects that have been positioned after getting tracked will be in the same position in world space
}
Make sure you do the following changes in the project:
(a) Extended tracking (device position tracker) is enabled.
(b) Set world center mode of Vuforia Behaviour in AR camera to "DEVICE".
I would recommend you try a mashup of two different components. Firstly you could use a normal target detection for the image. Then after you catch the event that the image was recognised, you would simply activate the Ground plane tracking (you can just prompt the user to look down and then tap or something similar).
The reason extended tracking doesn't work so well for you is that it is not designed to cary space tracking on its own it only remembers the image position roughly in its FOV so that different obstructions don't cause tracking issues.
Hope this helped clarify it a bit!
Im coding this game in c# (https://www.google.cz/search?q=vlacek+hra&source=lnms&tbm=isch&sa=X&ved=0ahUKEwjDtY7BosrTAhUDGZoKHfL5DuIQ_AUICCgB&biw=1280&bih=624#imgrc=dnnr33z9bcaNnM:), which is a czech version of the Snake, using Windows Forms and System.Drawing.
So far the behavior and functioning is not a problem, the doubt i have and i cannot answer is, is it possible to create and image, bitmap, graphic, rectangle or any of those objects that could work, made of the sum of small images. Being specific, each level of the game have the normal walls, plus the specific level walls, so how can i draw that wall or create an image or bitmap, made of the repetition of one image.
The problem is that i need to create the wall, from the sum of this small image https://github.com/PabloRodriz/Vlacek-hra-Train-Game-/blob/master/Snake%20Game/Images/wall.gif (here is where all the code i will be updating is) , which will go "inside" a rectangle object (Graphics.DrawImage(Image, Rectangle), cause i need the rectangles to check the collision with walls and the body of the train.
So how i draw the whole wall with just that image. A loop and draw multiple times the same image? Can i store all of that in a single image?
I'm assuming that you're using WinForms here. If this is WPF instead, let us know.
Instead of drawing bitmaps, why don't you use vector methods available within GDI+? You should store each level's walls configuration in memory (xml/whatever). These would probably all be sets of line segments (x1,y1 to x2,y2). Then upon invalidation, you can read current level's walls data and draw them within Paint event using e.Graphics.DrawLine() or e.Graphics.DrawRectangle() etc.
Make sure you Invalidate() your form/control in the timer you're using to create game frames. Many people make the mistake of creating the Graphics object within the timer event, causing severe impact on game responsiveness.
Your walls data should look something like this:
class Wall
{
public Point Start {get; set;}
public Point End {get; set;}
}
and the Level class would be something like
class Level
{
public string Name {get; set;}
public List<Wall> Walls {get; set;}
}
You can implement a collision detector within the Wall class, which would simply be a function that checks whether the snake's head (x,y) lies on that line segment.
I'm trying to interact with world space UI using a first person controller when Cursor.lockState is set to CursorLockMode.Locked.
world space UI and a character
But when cursor is locked, cursor position is set to (-1, -1),
which is told from the Inspector.
cursor position of (-1, -1)
I performed a graphic raycast with EventSystem.RaycastAll, Sreen.width/2 and PointerEventData. EventSystem.current.RaycastAll collects all UI objects in the middle of screen, but no events is sent to them.
I also tried ExecuteEvents.Execute<IEventSystemHandler> to manully send event to UI targets. This works for button when I send 'submit' event to it. Obviously this is not an elegant solution. I have no idea how to send message to slider either.
// manully send a 'submit' event to UI elements
List<RaycastResult> results = new List<RaycastResult>();
void Update() {
if (Input.GetButtonUp("Fire1")) {
PointerEventData data = new PointerEventData(EventSystem.current);
data.position = new Vector2(Screen.width / 2, Screen.height / 2);
EventSystem.current.RaycastAll(data, results);
foreach (var result in results) {
ExecuteEvents.ExecuteHierarchy<ISubmitHandler>(
result.gameObject, data,
ExecuteEvents.submitHandler
);
}
}
}
This crazy attempt works when played full-screen on Windows. 2333
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SetCursorPos ( int x , int y );
void SetCursorPositionToCenter()
{
SetCursorPos(Screen.width/2, Screen.height/2);
}
Relavant Resources
I had a lot of problems working with Graphics Raycaster and Global UI elements as well. I tried a lot of things as well but the event system didn't seem to work. But I was simulating a mouse with a touchpad and maybe I didn't completely simulate how a mouse works with UI elements.
I ended up abandoning graphics raycaster and instead add a box collider to all UI elements. That way a regular physics raycaster would be able to detect it and run some code. For the slider, it is just increasing the slider's value as your x or y of your pointer increase.
Hope this helps a little.
What you're doing with the submit handler is similar to the many different ways this can be done. I've not dealt with sliders specifically, because it's not very easy to control sliders in this method (player controller or, in the case of VR, the user's head, does not do straight lines very well). So for slider input we usually go with +/- buttons. Another idea could be that when the user is pointing at a UI element that you release the cursorLock when they click. When click is released you can resume cursor lock.
UI elements are also often in need of states like hover/onEnter, onExit, sometimes pointer up, and usually pointer down. So we've often used Selectable class for this. I think all the interactable UI elements inherit from this so it's a good spot to access the UI element from. This will usually trigger the proper events but it can be a little tricky. Examine some of the many readily available gaze input systems as they're doing the same thing. I don't think I've ever seen one handle sliders though (they're usually meant for VR and gaze-to-slider control would be bad UX).
Cheers and good luck!
If you're trying to access UI elements without affecting gameplay you can simply set Time.TimeScale = 0; which basically pauses time but UI elements will still be active. Then just unlock your cursor and use it freely.
I'm making a particle game with (So far, only water), and the Draw() method inside an element is quite slow with a few going at once. I assume it's because it's calculating so much every second, but I'm still quite unhappy with it, considering they're just basic 2D shapes. How can I make it more efficient?
Here's my code:
(Loop) (Ran every 50 miliseconds) (Note, I just included Forms for the timer, I'm using WPF.)
void TimeKeeper_Tick(object sender, EventArgs e)
{
foreach (Element ele in Elements)
{
ele.Draw();
}
}
And draw method. Pos is a "Vector2" (Class I made to save me time):
public void Draw()
{
Pos.Add(3, 10);
if (Pos.Y > (int)canvas.ActualHeight)
{
Pos.Set(Pos.X, (int)shape.RenderSize.Width);
}
if (Pos.X+shape.RenderSize.Width > (int)canvas.ActualWidth)
{
Pos.Set(0, Pos.Y+(int)shape.RenderSize.Height);
}
shape.SetValue(Canvas.LeftProperty, (double)Pos.X);
shape.SetValue(Canvas.TopProperty, (double)Pos.Y);
if (canvas.Children.IndexOf(shape) != null)
{
canvas.Children.Remove(shape);
}
canvas.Children.Add(shape);
}
Overriding Canvas.OnRender in a Canvas descendant is your best bet for lots of moving shapes.
WPF optimizes for static shapes. If you move all those static shapes around, you go through all the overhead of this optimization without benefitting from it (as the shapes move).
The code looks something like this:
public delegate void RenderEventHandler(CanvasRender sender, DrawingContext dc);
public class CanvasRender : Canvas
{
public event RenderEventHandler Render;
public CanvasRender()
{
}
protected override void OnRender(DrawingContext dc)
{
if (Render != null)
Render(this, dc);
base.OnRender(dc);
}
}
You then use this class instead of Canvas, and assign a handler to the Render event. In that event, you redraw your entire visual using explicit calls to the DrawingContext.
It may sound like you're doing much more work this way, but this actually is way more efficient than creating all the moving objects and then moving them around. Especially if those objects are lines whose angle/length changes over time, as WPF can't pre-render them and the pre-rendered shape when it moves.
If you want it to be really fast, you have to use some advanced techniques. Particularly these are so called Procedural Animations and animations using Writable Bitmaps.
Here is an excellent blog post describing those techniques (with an example of the particle effect): http://blogs.claritycon.com/blog/2011/03/30/advanced-animation-animating-15000-visuals-in-silverlight-2/. It is about Silverlight, but because Silverlight is a subset of WPF the techniques are the same.
A lot depends on what you consider 'slow'
If you move the shapes every 50 ms you have to move them more each interval to make them go faster.
But adding a timer like you did is not the best way to create animations in WPF.
There are a couple of options:
specify a speed for each shape (something like: 10 units per second), then with each update of the screen move the shapes according to the time that passed since the last time it has been moved and its speed. So you need to keep track of the time elapsed too.
Create Storyboards, they have their own timers (timelines) so all you have to do is set the start and the end position and specify the duration and finally Play the animation.