I'm doing some animation script in RPG Maker XP (made with ruby) that allow you to display moving images. My question here is not strictly about RPG Maker, but in general term. This is the code I found out so far and it works, but with problem :
class Poser
attr_accessor :images
def initialize
#images = Sprite.new
#images.bitmap = RPG::Cache.picture('Character.png') #display picture
#images.x = 540 #place it on the bottom right corner of the screen
#images.y = 180
end
def move(x,y)
#images.x += x
#images.y += y
end
def animate(x,y,step,delay) #Animate moving the picture up and down with delay
forward = true
2.times { #the first loop, do code 2 times of :
step.times {
wait(delay) #wait x frame
if forward
move(x/step,y/step) #move the picture down
else
move(-x/step,-y/step) #move the picture up
end
}
wait(delay*3)
forward = false
}
end
def wait(time)
while time > 0
time -= 1
Graphics.update
end
end
end
Then I create an instance of it and called the method :
$test = Poser.new
$test.animate(0,10,10,10)
What the above code do is to move the picture up and down (just like breathing animation, your head bob up and down)
As you can see, Im using loop functions to move the picture with delay. What I got is, I cannot do anything else until the animation finished. What I meant by "anything else" is such as walking around with my character, talk to NPC, I want to do those things while there is animation being played in the background. In the end, the game "paused" in the loop block.
Is there is another way to do animation without looping, or, anything that doesn't "pause" the screen until animation is finished ? Thanks in advance.
Usually, games use a system called a game loop. A game loop is a loop in the main function of the program that executes as fast as it can. Each time it executes, it executes two functions (or these can be the body of the loop, that's a design choice that you can make): draw and update (update, then draw).
update's job is to change the positions of characters, usually by a formula of position=(x+pixelsPerSecond*secondsSinceLastTick,y+pixelsPerSecond*secondsSinceLastTick) (in game terminology, a tick is an iteration of the game loop). The system of a game loop is optimized for games, because every tick you can execute one tiny piece of each animation, fast enough together that they give an illusion of concurrency (game loops run many times per second).
After update has changed the position of entire objects (eg. a fast NPC is now 5 pixels further to the left), draw is used to draw the scene. draw can do a couple of things. It can draw sprites at the locations indicated by update, and it can also maintain it's own animations (small things like the animation of legs walking -- update shouldn't set the position of the legs in the walking animation, just the new position of the character for this tick).
I'm not sure if I am exactly answering your question, as I know nothing about RPG Maker (so maybe you have to do something else completely), but because you said in general, this is what it is.
Related
I am trying to plot a set of 3D trajectories in a single plot in Julia. By 3-D trajectories I mean: different sets of 3-D coordinates over time. These trajectories are stored in a multidimensional array called positions, where the dimensions respectively correspond to the Trajectory ID, X-Y-Z coordinate and Time. For example, positions[75,2,1:100] refers to the Y (2nd) coordinate of the 75th Trajectory, across the first 100 timesteps of the trajectory.
I am trying to figure out why the following code doesn't work:
using Plots
plotlyjs()
time_indices = 1:100
ax= scatter3d(positions[1,1,time_indices],positions[1,2,time_indices],positions[1,3,time_indices],label="Trajectory 1 for times 1 to 100")
for n in 2:size(positions,1)
scatter3d!(ax, positions[n,1,time_indices], positions[n,2,time_indices],positions[n,3,time_indices],label="Trajectory $n for times 1 to 100")
end
When I run that code, I don't see anything in the Plots window (I'm using Atom), although I don't get any errors / it appears to run successfully. Any thoughts on what I'm doing wrong? Should I use a different backend? It doesn't work on either gr() or plotlyjs() (those are the only ones I know of, based on tutorials I've completed).
Follow up question: once I can successfully plot such 3-D trajectories in a single static plot, I am wondering how you would go about animating them over time (using #gif or #animate macros, presumably)? I am asking this here, because I wasn't able to understand the documentation / tutorial on 3D animations, unfortunately. Googling / other sources have also not helped :(
It looks like you're just missing a display(ax) at the end, after the loop.
Edit: to animate, try
anim = #animate for n in 1:size(positions,1)
scatter3d(positions[n,1,time_indices], positions[n,2,time_indices],positions[n,3,time_indices],label="Trajectory $n for times 1 to 100")
end
gif(anim, "some_file_name.gif", fps=15)
(or if you want the prior trajectories to show up as well in later frames of the gif, then replace the scatter3d with scatter3d!)
I can't test the above without having your positions, but here is another example that I have just tested on Julia 1.5.0beta with Plots and the GR backend:
using Plots; gr();
anim = #animate for i=1:100
plot(sin.(range(0,i/10*pi,length=1000)), label="", ylims=(-1,1))
end
gif(anim, "anim_fps15.gif", fps=15)
How to do the second bit (the animation - see details in comments on the accepted answer):
gr()
anim = #animate for t in time_indices
all_positions_t = positions[:,:,t] # positions of all trajectories at time t
scatter3d(all_positions_t[:,1], all_positions_t[:,2],all_positions_t[:,3],label="")
end
gif(anim, "some_file_name.gif", fps=15)
I have a GSAP (Greensock) animation that is "seemless," meaning that when it is played on an infinite loop you can't tell which part is the beginning, and which is the end.
Let's say I have two labels, one near the start (about 10% of the way in) and another near the end (around 90% completed):
| start end |
|----|----|----|----|----|----|----|----|----|
If I create a tweenTo from 'start' to 'end', it'll go "the long ways", scrubbing the playhead forward from 10% over to 90%.
Tween from 'start' to 'end' would go
"long ways" from the left to the right
:==================================>
| start end |
|----|----|----|----|----|----|----|----|----|
So far so good, this makes sense to me.
But what if I don't want that to happen? Since my animation is seemless, technically the animation could start at 10% and go backwards until it reaches the beginning, then loops around to the end of the animation and continues in reverse until it reaches the 'end' label at 90%.
But what if I wanted to go "backwards" from
'start' and loop around to 'end'?
/====: <====/
| start end |
|----|----|----|----|----|----|----|----|----|
This would be the "short way" between those two labels.
My question is, how would I go about creating an effect like this?
That is, if I have two labels, is it possible to animate between them where my animation "wraps around" the timeline instead of staying contained within the timeline?
See the following codepen for an example of this - https://codepen.io/romellem/pen/yQOQar?editors=0010
Within that codepen, on the left is the issue I'm facing, and on the right is a faked" example that shows what I want the animation on the left to do when tweening "around" my two labels.
I frequently get myself into trouble when I've put together a complex animation in Maya with lots of rigs and connections and animated attributes and then find that I need to insert 100 frames somewhere in my 5000 frame animation to make space for additional animation. In the past, I've struggled with selecting all objects and all of their keyframes to move them down the timeline as it seems that I always miss some attributes that don't get moved and then things get ugly and I waste a lot of time fixing things.
I feel like there must be a more elegant way to insert a certain number of frames into the timeline easily without worrying that some keyframes will be left behind. I've tried my luck with the dope sheet, but I don't really find it any easier to use than the graph editor.
"Elegant" in this case is in the eye of the beholder.
Effectively what you need to do is move all the keys after a given point by a given amount. The hard part is that moving the keys will change the meaning of the curves: the interpolation is going to change no matter what you do unless you've got locked tangents on both sides of the change.
if you just want to insert keys at a particular point in time, it'll look like this:
def move_keys_after(start, time_shift):
key_string = '%s:' % start
for curve in cmds.ls(type='animCurve'):
before = cmds.keyframe(curve, q=True)
cmds.keyframe(curve, r = True, tc = time_shift, t = (key_string,), iub=True)
after = cmds.keyframe(curve, q=True)
print curve, before, "->", after
move_keys_after( 10, 20)
That example moves all of the keys in the scene after time start by time_shift frames. If you want to limit this to an object you could get the anim curves from the object directly or use the animation flag of the keyframe command
I understand that game development involves a 'game loop', in which the scene is drawn. This game loop either runs as fast as possible (no timer, frame animation) or is called based on a timer (timer animation). I'm curious as to how advanced animation (something beyond just simple geometry) is actually done, considering how many frames might take place in say, a character walking. Obviously the programmer has not hard-coded in the position of the character's foot at every frame of the animation, so I'm wondering how this would actually be done?
If any clarification of the question is necessary, I'll be happy to fill more in.
I want to write a paint program in the style of MS Paint.
For painting things on screen when the user moves the mouse, I have to wait for mouse move events and draw on the screen whenever I receive one. Apparently, mose move events are not sent very often, so I have to interpolate the mouse movement by drawing a line between the current mouse position and the previous one. In pseudocode, this looks something like this:
var positionOld = null
def handleMouseMove(positionNew):
if mouse.button.down:
if positionOld == null:
positionOld = positionNew
screen.draw.line(positionOld,positionNew)
positionOld = positionNew
Now my question: interpolating with straight line segments looks too jagged for my taste, can you recommend a better interpolation method? What method do GIMP or Adobe Photoshop implement?
Alternatively, is there a way to increase the frequency of the mouse move events that I receive? The GUI framework I'm using is wxWidgets.
GUI framework: wxWidgets.
(Programming language: Haskell, but that's irrelevant here)
EDIT: Clarification: I want something that looks smoother than straight line segments, see the picture (original size):
EDIT2: The code I'm using looks like this:
-- create bitmap and derive drawing context
im <- imageCreateSized (sy 800 600)
bitmap <- bitmapCreateFromImage im (-1) -- wxBitmap
dc <- memoryDCCreate -- wxMemoryDC
memoryDCSelectObject dc bitmap
...
-- handle mouse move
onMouse ... sw (MouseLeftDrag posNew _) = do
...
line dc posOld posNew [color := white
, penJoin := JoinRound
, penWidth := 2]
repaint sw -- a wxScrolledWindow
-- handle paint event
onPaint ... = do
...
-- draw bitmap on the wxScrolledWindow
drawBitmap dc_sw bitmap pointZero False []
which might make a difference. Maybe my choices of wx-classes is why I'm getting a rather low frequency of mouse move events.
Live demos
version 1 - more smooth, but more changing while you draw: http://jsfiddle.net/Ub7RV/1/
version 2 - less smooth but more stable: http://jsfiddle.net/Ub7RV/2/
The way to go is
Spline interpolation of the points
The solution is to store coordinates of the points and then perform spline interpolation.
I took the solution demonstrated here and modified it. They computed the spline after you stop drawing. I modified the code so that it draws immediately. You might see though that the spline is changing during the drawing. For real application, you probably will need two canvases - one with the old drawings and the other with just the current drawing, that will change constantly until your mouse stops.
Version 1 uses spline simplification - deletes points that are close to the line - which results in smoother splines but produce less "stable" result. Version 2 uses all points on the line and produces much more stable solution though (and computationally less expensive).
You can make them really smooth using splines:
http://freespace.virgin.net/hugo.elias/graphics/x_bezier.htm
But you'll have to delay the drawing of each line segment until one frame later, so that you have the start and end points, plus the next and previous points available for the calculation.
so, as I see the problem of jagged edge of freehand made curve, when the mouse are moved very fast, is not solved !!! In my opinion there are need to work around with the polling frequency of mousemove event in the system i.e. using different mouse driver or smf.. And the second way is the math.. using some kind of algorithm, to accuratly bend the straight line between two points when the mouse event is polled out.. For clear view you can compare how is drawed free hand line in photoshop and how in mspaint.. thanks folks.. ;)
I think you need to look into the Device Context documentation for wxWidgets.
I have some code that draws like this:
//screenArea is a wxStaticBitmap
int startx, starty;
void OnMouseDown(wxMouseEvent& event)
{
screenArea->CaptureMouse();
xstart = event.GetX();
ystart = event.GetY();
event.Skip();
}
void OnMouseMove(wxMouseEvent& event)
{
if(event.Dragging() && event.LeftIsDown())
{
wxClientDC dc(screenArea);
dc.SetPen(*wxBLACK_PEN);
dc.DrawLine(startx, starty, event.GetX(), event.GetY());
}
startx = event.GetX();
starty = event.GetY();
event.Skip();
}
I know it's C++ but you said the language was irrelevant, so I hope it helps anyway.
This lets me do this:
which seems significantly smoother than your example.
Interpolating mouse movements with line segments is fine, GIMP does it that way, too, as the following screenshot from a very fast mouse movement shows:
So, smoothness comes from a high frequency of mouse move events. WxWidgets can do that, as the example code for a related question demonstrates.
The problem is in your code, Heinrich. Namely, drawing into a large bitmap first and then copying the whole bitmap to the screen is not cheap! To estimate how efficient you need to be, compare your problem to video games: a smooth rate of 30 mouse move events per second correspond to 30fps. Copying a double buffer is no problem for modern machines, but WxHaskell is likely not optimized for video games, so it's not surprising that you experience some jitter.
The solution is to draw only as much as necessary, i.e. just the lines, directly on the screen, for example as shown in the link above.
I agree with harviz - the problem isn't solved. It should be solved on the operating system level by recording mouse movements in a priority thread, but no operating system I know of does that. However, the app developer can also work around this operating system limitation by interpolating better than linear.
Since mouse movement events don't always come fast enough, linear interpolation isn't always enough.
I experimented a little bit with the spline idea brought up by Rocketmagnet.
Instead of putting a line between two points A and D, look at the point P preceding A and use a cubic spline with the following control points B = A + v' and C = D - w', where
v = A - P,
w = D - A,
w' = w / 4 and
v' = v * |w| / |v| / 4.
This means we fall into the second point with the same angle as the line interpolation would, but go out a starting point in the same angle the previous segment came in, making the edge smooth. We use the length of the segment for both control point distances to make the size of the bend fit its proportion.
The following picture shows the result with very few data points (indicated in grey).
The sequence starts at the top left and ends in the middle.
There is still some level of uneasiness here which may be alleviated if one uses both the previous and the next point to adjust for both angles, but that would also mean to draw one point less than what one has got. I find this result already satisfactory, so I didn't try.